package terrain;


import java.io.Serializable;
import java.util.ArrayList;

import regles.Regle;


/**
 * Représente le terrain global (contient une collection de CaseTerrain)
 * @author Alexis BRASY, Geoffrey LEQUESNE, Sandrine PIRIOU, Michel POPOV
 *
 */
public class Terrain implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * Tableau à deux dimensions contenant des CaseTerrain.
     */
    private ArrayList<ArrayList<CaseTerrain>> terrain;
	
    /**
     * Règles utilisées pour toutes les actions des unités relatives à ce terrain.
     */
    private Regle regles;
	
    /**
     * Constructeur d'un terrain de taille 30x20
     */
    public Terrain() {// this (30, 20, new Regle());
    }
	
    /**
     * Constructeur du terrain avec deux paramètres
     * (nombre de lignes i et nombre de colonnes j)
     * @param nb_lignes nombre de lignes du terrain
     * @param nb_colonnes nombre de colonnes du terrain
     */
    public Terrain(int nb_lignes, int nb_colonnes, Regle regles) {
        this.regles = regles;
        terrain = new ArrayList<ArrayList<CaseTerrain>>();
        terrain.ensureCapacity(nb_colonnes);
        for (int i = 0; i < nb_colonnes; i++) {
            terrain.add(i, new ArrayList<CaseTerrain>());
            terrain.get(i).ensureCapacity(nb_lignes);
            for (int j = 0; j < nb_lignes; j++) {
                terrain.get(i).add(j,
                        new CaseTerrain(new Coordonnees(i, j), this));
                terrain.get(i).get(j).setTypeTerrain(TypeTerrain.PLAINE);
            }
        }
    }

    /**
     * Getter de l'attribut regles.
     * @return regles
     */
    public Regle getRegles() {
        return regles;
    }

    /**
     * Accesseur sur une case précise du terrain.
     * @param coord
     * @return La case du terrain correspondant aux coordonnées passées en paramètre.
     */
    public CaseTerrain getCase(Coordonnees coord) {
        return terrain.get(coord.getX()).get(coord.getY());
    }
	
    /**
     * Accesseur sur une case précise du terrain.
     * @param x Coordonnée X de la case à laquelle on souhaite accéder.
     * @param y Coordonnée Y de la case à laquelle on souhaite accéder.
     * @return La case du terrain correspondant aux coordonnées passées en paramètre.
     */
    public CaseTerrain getCase(int x, int y) {
        Coordonnees coord = new Coordonnees(x, y);

        return terrain.get(coord.getX()).get(coord.getY());
    }
	
    /**
     * Getter du nombre de lignes que contient le tableau terrain
     * @return le nombre de lignes
     */
    public int getNbLignes() {
        return this.terrain.size();
    }
	
    /**
     * Getter du nombre de colonnes que contient le tableau terrain
     * @return le nombre de colonnes
     */
    public int getNbColonnes() {
        return this.terrain.get(0).size();
    }

    /**
     * Fonction qui affiche dans la console les coordonnées de toutes les
     * cases du tableau ainsi que leur type
     */
    public void afficher() {
        String str = null;

        for (int i = 0; i < terrain.size(); i++) {
            for (int j = 0; j < terrain.get(i).size(); j++) {
                str = "(" + i + "," + j + ")";
                switch (terrain.get(i).get(j).getTypeTerrain()) {
                case PLAINE:
                    str = str + "PLAINE";
                    break;

                case MER:
                    str = str + "MER";
                    break;

                case SABLE:
                    str = str + "SABLE";
                    break;

                case VIDE:
                    str = str + "VIDE";
                    break;

                case MONTAGNE:
                    str = str + "MONTAGNE";
                    break;
                }
                
            }
        }
		
    }
	
    /**
     * Fonction de redimensionnement du terrain.
     * @param newI Nouvelle hauteur du terrain
     * @param newJ Nouvelle largeur du terrain
     */
    public void redimTerrain(int newI, int newJ) {
        int oldJ = terrain.get(0).size();

        // gestion de la nouvelle taille en I
        if (newI > terrain.size()) {
            terrain.ensureCapacity(newI);
            for (int i = terrain.size(); i < newI; i++) {
                terrain.add(i, new ArrayList<CaseTerrain>());
                terrain.get(i).ensureCapacity(newJ);
                for (int j = 0; j < newJ; j++) {
                    terrain.get(i).add(j,
                            new CaseTerrain(new Coordonnees(i, j), this));
                    terrain.get(i).get(j).setTypeTerrain(TypeTerrain.PLAINE);
                }
            }
        } else if (newI < terrain.size()) {
            while (newI < terrain.size()) {
                terrain.remove(terrain.size() - 1);
            }
        }

        // gestion de la nouvelle taille en J
        for (int i = 0; i < newI; i++) {
            if (newJ > oldJ) {
                terrain.get(i).ensureCapacity(newJ);
                for (int j = oldJ; j < newJ; j++) {
                    terrain.get(i).add(j,
                            new CaseTerrain(new Coordonnees(i, j), this));
                    terrain.get(i).get(j).setTypeTerrain(TypeTerrain.PLAINE);
                }
            } else if (newJ < oldJ) {
                while (newJ < terrain.get(i).size()) {
                    terrain.get(i).remove(terrain.get(i).size() - 1);
                }
            }
        }
		
    }
}
